package com.hb.evaluator;

import com.hb.domain.Spittle;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;

import java.io.Serializable;

/**
 * SpittlePermissionEvaluator 实现了 Spring Security 的 PermissionEvaluator 接口，它需要实现两个不同的 hasPermission() 方法。
 * 其中的一个 hasPermission() 方法把要评估的对象作为第二个参数。第二个 hasPermission() 方法在只有目标对象的 ID 可以得到的时候才有用，
 * 并将 ID 作为 Serializable 传入第二个参数。
 */
public class SpittlePermissionEvaluator implements PermissionEvaluator {
    private static final GrantedAuthority ADMIN_AUTHORITY = new GrantedAuthorityImpl("ROLE_ADMIN");

    /**
     * 对于第一个 hasPermission() 方法，要检查所评估的对象是否为一个 Spittle，并判断所检查的是否为删除权限。如果是这样，它将对比 Spitter 的用户名是否与认证用
     * 户的名称相等，或者当前用户是否具有 ROLE_ADMIN 权限。
     * @param authentication
     * @param o
     * @param o1
     * @return
     */
    @Override
    public boolean hasPermission(Authentication authentication, Object o, Object o1) {
        if (o instanceof Spittle) {
            Spittle spittle = (Spittle) o;
            String username = spittle.getSpitter().getUsername();
            if ("delete".equals(o1)) {
                return isAdmin(authentication) || username.equals(authentication.getName());
            }
        }

        throw new UnsupportedOperationException("hasPermission not supported for object <" + o + "> and permission <" + o1 + ">");
    }

    /**
     * 为了满足我们的需求，我们假设使用 Spittle 对象来评估权限，所以第二个方法只是简单地抛出 UnsupportedOperationException。
     * @param authentication
     * @param serializable
     * @param s
     * @param o
     * @return
     */
    @Override
    public boolean hasPermission(Authentication authentication, Serializable serializable, String s, Object o) {
        throw new UnsupportedOperationException();
    }

    private boolean isAdmin(Authentication authentication) {
        return authentication.getAuthorities().contains(ADMIN_AUTHORITY);
    }
}
